package com.googlecode.animator.view.viewport
{
	import com.googlecode.animator.data.Notifications;
	import com.googlecode.animator.data.cameras.ActualViewCameraVO;
	import com.googlecode.animator.data.cameras.CameraVO;
	import com.googlecode.animator.data.objects3d.Object3DVO;
	import com.googlecode.animator.data.viewports.ViewportVO;
	import com.googlecode.animator.view.viewselector.ViewSelector;
	
	import org.papervision3d.core.geom.renderables.Vertex3D;
	import org.papervision3d.materials.special.LineMaterial;
	import org.papervision3d.objects.DisplayObject3D;
	import org.puremvc.as3.interfaces.INotification;
	
	public class MainViewportMediator extends ViewportMediator
	{
		protected static var _drawline:DrawLine;
		
		public static const DRAWLINE_NAME:String = "drawline";
		
		public function MainViewportMediator(viewComponent:Viewport)
		{
			super(viewComponent);
		}
		
		/**
		 * Triggered by PureMVC framework. 
		 * 
		 */
		override public function onRegister():void
		{
			super.onRegister();
			
		}
		
		/**
		 * Lists notification of interests. 
		 * @return 
		 * 
		 */
		override public function listNotificationInterests():Array
		{
			var list:Array = super.listNotificationInterests();
			
			list.push(Notifications.VIEWPORT_ADDED);
			
			return list;
		}
		
		/**
		 * Handles notification of interests. 
		 * @param notification
		 * 
		 */
		override public function handleNotification(notification:INotification):void
		{
			super.handleNotification(notification);

			switch(notification.getName())
			{
					
				case Notifications.VIEWPORT_ADDED:
				
					handleViewportAdded(notification.getBody() as ViewportVO);
					
					break;
					
			}
		}		
		
		override protected function handleObject3DAdded(object3D:Object3DVO):void
		{
			// calling the super class ensures the names of the TargetProxy and the CameraProxy are registered
			super.handleObject3DAdded(object3D);
			
			// if both the TargetProxy and the CameraProxy are present, we can make the line that joins them
			if(_targetProxy != null && _cameraProxy != null)
			{
				makeCameraLine(settings.scene.getChildByName(_cameraProxy), settings.scene.getChildByName(_targetProxy));

				setCameraProxiesVisiblity(settings.getCamera(viewRef.currentCamera));			
			}		
			
		}
		
		/**
		 * Handles a 3D object being deleted. 
		 * 
		 */
		override protected function handleObject3DDeleted(name:String):void
		{
			super.handleObject3DDeleted(name);
			
			viewRef.removeViewportObject3D(name);
			
		}
		
		override protected function handleObject3DMoved():void
		{
			
			
			var cameraProxy:DisplayObject3D = settings.scene.getChildByName(_cameraProxy);
			var targetProxy:DisplayObject3D = settings.scene.getChildByName(_targetProxy);
			
			if(cameraProxy != null && targetProxy != null)
			{
				cameraProxy.lookAt(targetProxy);
				updateCameraLine(cameraProxy, targetProxy);
			}
			
			super.handleObject3DMoved();
		}
		
		override protected function handleViewSelectorChange(vs:ViewSelector):void
		{	
			var camera:CameraVO = vs.selectedItem as CameraVO;
			camera = settings.getCamera(camera.name);
			
			if(_cameraProxy && _targetProxy)
			{
				setCameraProxiesVisiblity(camera);
			} 
			
			super.handleViewSelectorChange(vs);
		}	
		
		/**
		 * Handles the resetting of the project.
		 * @param viewports
		 * 
		 */
		override protected function handleProjectIsReset():void
		{
			_drawline.removeAllLines();
			
			super.handleProjectIsReset();
		}
		
		/**
		 * Sets the camera and target proxies to invisible if the viewport is 
		 * using the camera with the role actualView.
		 * @param camera
		 * 
		 */
		protected function setCameraProxiesVisiblity(camera:CameraVO):void
		{
			if(camera is ActualViewCameraVO)
			{
				viewRef.makeViewportObject3DInvisible(_cameraProxy);
				viewRef.makeViewportObject3DInvisible(_targetProxy);
				viewRef.makeViewportObject3DInvisible(DRAWLINE_NAME);
			
			}else
			{
				viewRef.makeViewportObject3DVisible(_cameraProxy);
				viewRef.makeViewportObject3DVisible(_targetProxy);
				viewRef.makeViewportObject3DVisible(DRAWLINE_NAME);
			}
		} 
		/**
		 * Draws a line between the CameraProxy and the TargetProxy. 
		 * @param camera
		 * @param target
		 * 
		 */
		public function makeCameraLine(camera:DisplayObject3D, target:DisplayObject3D):void
		{
			if(_drawline == null)
			{
				var vt1:Vertex3D = getVertex3D(camera);
				var vt2:Vertex3D = getVertex3D(target);
					
				var lm:LineMaterial = new LineMaterial(0xff0000);
				_drawline = new DrawLine(lm, vt1, vt2);
				_drawline.name = DRAWLINE_NAME;
			}
			
			
			settings.scene.addChild(_drawline);
		}
		
		/**
		 * Updates the line drawn between the CameraProxy and the TargetProxy. 
		 * @param object3D1
		 * @param object3D2
		 * 
		 */
		public function updateCameraLine(object3D1:DisplayObject3D, object3D2:DisplayObject3D):void
		{
			_drawline.update(getVertex3D(object3D1), getVertex3D(object3D2));
		}
		
		/**
		 * Returns the vertex of a DisplayObject3D. 
		 * @param object3D
		 * @return 
		 * 
		 */
		protected function getVertex3D(object3D:DisplayObject3D):Vertex3D
		{
			return new Vertex3D(object3D.x, object3D.y, object3D.z); 
		}
	}
}